package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.OrdersPageQueryDTO;
import com.sky.dto.OrdersPaymentDTO;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.DistanceExceedsException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.*;
import com.sky.properties.BaiduMapProperties;
import com.sky.result.PageResult;
import com.sky.service.OrderService;
import com.sky.utils.HttpClientUtil;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import com.sky.websocket.WebSocketServer;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private BaiduMapProperties baiduMapProperties;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口，生成预支付交易单
        JSONObject jsonObject = weChatPayUtil.pay(
                ordersPaymentDTO.getOrderNumber(), //商户订单号
                new BigDecimal(0.01), //支付金额，单位 元
                "苍穹外卖订单", //商品描述
                user.getOpenid() //微信用户的openid
        );

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw new OrderBusinessException("该订单已支付");
        }

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));

        return vo;
    }

    /**
     * 支付成功，修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);

        //支付成功后向客户端推送来单提醒 websocket
        Map map = new HashMap();
        map.put("type", 1);
        map.put("orderId", ordersDB.getId());
        map.put("content", "订单号：" + outTradeNo);
        String jsonString = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(jsonString);
    }




    /**
     * 距离校验
     * @param address
     * @return
     */
    private void checkDistance(String address) {

        //地理编码API服务基础地址
        String baseURL = "https://api.map.baidu.com/geocoding/v3/";
        //路线规划API服务基础地址
        String baseURL2 = "https://api.map.baidu.com/directionlite/v1/driving";

        //*********************************商家地址获取***********************************************//
        Map<String, String> paramMap = new HashMap<>();
        //设置拼接参数
        paramMap.put("address", baiduMapProperties.getAddress());
        paramMap.put("output", "json");
        paramMap.put("ak", baiduMapProperties.getAk());

        //发送请求，接收响应数据
        String response = HttpClientUtil.doGet(baseURL, paramMap);
        //解析响应数据，获取经纬度信息（商家）
        JSONObject jsonObject = JSON.parseObject(response);
        JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
        float lng = location.getFloatValue("lng");
        float lat = location.getFloatValue("lat");

        //*********************************用户地址获取***********************************************//
        Map<String, String> paramMapClient = new HashMap<>();
        //设置拼接参数
        paramMapClient.put("address", address);
        paramMapClient.put("output", "json");
        paramMapClient.put("ak", baiduMapProperties.getAk());

        //发送请求，接收响应数据
        String responseClient = HttpClientUtil.doGet(baseURL, paramMapClient);
        //解析响应数据，获取经纬度信息（用户）
        JSONObject jsonObjectClient = JSON.parseObject(responseClient);
        JSONObject locationClient = jsonObjectClient.getJSONObject("result").getJSONObject("location");
        float lngClient = locationClient.getFloatValue("lng");
        float latClient = locationClient.getFloatValue("lat");

        //*********************************距离计算*************************************************//
        Map<String, String> paramMapRoute = new HashMap<>();
        //设置拼接参数
        paramMapRoute.put("origin", String.valueOf(lat) + "," + String.valueOf(lng) );
        paramMapRoute.put("destination", String.valueOf(latClient) + "," + String.valueOf(lngClient));
        paramMapRoute.put("ak", baiduMapProperties.getAk());
        //发送请求，接收响应数据
        String responseRoute = HttpClientUtil.doGet(baseURL2, paramMapRoute);
        //解析响应数据，获取商家距用户的距离
        JSONObject jsonObjectRoute = JSON.parseObject(responseRoute);
        int status = jsonObjectRoute.getIntValue("status");
        String message = jsonObjectRoute.getString("message");
        String result = jsonObjectRoute.getString("result");
        JSONObject route = jsonObjectRoute.getJSONObject("result").getJSONArray("routes").getJSONObject(0);
        int distance = route.getIntValue("distance");

        if(distance >= 5000) {
            //若超出五公里距离，则抛出异常
            throw new DistanceExceedsException(MessageConstant.DISTANCE_EXCEEDS);
        } else
            return;
    }

    /**
     * 订单提交
     * @param ordersSubmitDTO
     * @return
     */
    @Transactional
    public OrderSubmitVO submit(OrdersSubmitDTO ordersSubmitDTO) {

        Long addressBookId = ordersSubmitDTO.getAddressBookId();
        //判断用户是否在五公里配送距离内
        checkDistance(addressBookMapper.selectAddress(addressBookId));

        //处理各种异常情况（地址簿为空/购物车为空）
        AddressBook addressBook = addressBookMapper.getById(addressBookId);
        if(addressBook == null) {
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }

        Long userId = BaseContext.getCurrentId();
        ShoppingCart shoppingCart = ShoppingCart.builder()
                .userId(userId)
                .build();
        List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);
        if(list == null && list.size() == 0) {
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }

        //向orders表中插入一条数据
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO, orders);
        orders.setOrderTime(LocalDateTime.now());
        orders.setConsignee(addressBook.getConsignee());
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        orders.setPayStatus(Orders.UN_PAID);
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setPhone(addressBook.getPhone());
        orders.setUserId(userId);

        orderMapper.insert(orders);

        //向order_detail表中插入多条数据
        List<OrderDetail> orderDetails = new ArrayList<>();
        for(ShoppingCart cart : list) {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart, orderDetail);
            orderDetail.setOrderId(orders.getId());
            orderDetails.add(orderDetail);
        }
        orderDetailMapper.insertBatch(orderDetails);

        // 清空购物车
        shoppingCartMapper.clean(userId);

        //封装OrderSubmitVo
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                .id(orders.getId())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .build();

        return orderSubmitVO;
    }

    /**
     * 订单分页查询
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult selectByPage(OrdersPageQueryDTO ordersPageQueryDTO) {
        //设置用户id
        Long userId = BaseContext.getCurrentId();
        ordersPageQueryDTO.setUserId(userId);

        //分页查询
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        Page<Orders> orders = orderMapper.selectByPage(ordersPageQueryDTO);

        //构造List<orderVO>对象
        List<OrderVO> records = new ArrayList<>();

        if(orders != null && orders.size() > 0) {
            //循环取出订单id
            for(Orders order : orders) {
                Long orderId = order.getId();
                List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(orderId);

                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(order, orderVO);
                //设置订单详情信息
                orderVO.setOrderDetailList(orderDetails);
                //设置订单菜品信息
                orderVO.setOrderDishes(orderDetailMapper.selectNameByOrderId(orderId));

                records.add(orderVO);
            }
        }

        return new PageResult(orders.getTotal(), records);
    }

    /**
     * 根据订单id查询订单详情
     * @param id
     * @return
     */
    public OrderVO selectByOrderId(Long id) {
        //根据订单id查询订单
        Orders orders = orderMapper.selectByOrderId(id);
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders, orderVO);

        //设置订单对应的订单详细信息
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(id);
        orderVO.setOrderDetailList(orderDetails);
        //设置订单对应的地址
        Long addressBookId = orderMapper.selectAddressBookId(id);
        orderVO.setAddress(addressBookMapper.selectAddress(addressBookId));

        return orderVO;
    }

    /**
     * 改变订单状态
     * @param id
     */
    public void statusChange(Long id, Integer status) {
        orderMapper.statusChange(id, status);
    }

    /**
     * 再来一单（添加购物车）
     * @param id
     */
    public void orderAgain(Long id) {
        //根据订单id查询订单明细
        List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(id);

        List<ShoppingCart> list = new ArrayList<>();
        //将明细表中每条数据依次插入购物车表中
        for(OrderDetail orderDetail : orderDetails) {
            ShoppingCart shoppingCart = new ShoppingCart();
            shoppingCart.setUserId(BaseContext.getCurrentId());
            shoppingCart.setCreateTime(LocalDateTime.now());

            BeanUtils.copyProperties(orderDetail, shoppingCart);
            shoppingCartMapper.insert(shoppingCart);
        }

    }

    /**
     * 各个状态订单数量统计
     * @return
     */
    public OrderStatisticsVO numCount() {
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();

        orderStatisticsVO.setToBeConfirmed(orderMapper.count(Orders.TO_BE_CONFIRMED));
        orderStatisticsVO.setConfirmed(orderMapper.count(Orders.CONFIRMED));
        orderStatisticsVO.setDeliveryInProgress(orderMapper.count(Orders.DELIVERY_IN_PROGRESS));

        return orderStatisticsVO;
    }

    /**
     * 订单分页查询
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult selectByPage2(OrdersPageQueryDTO ordersPageQueryDTO) {

        //分页查询
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        Page<Orders> orders = orderMapper.selectByPage(ordersPageQueryDTO);

        //构造List<orderVO>对象
        List<OrderVO> records = new ArrayList<>();

        if(orders != null && orders.size() > 0) {
            //循环取出订单id
            for(Orders order : orders) {
                Long orderId = order.getId();
                List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(orderId);

                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(order, orderVO);
                //设置订单详情信息
                orderVO.setOrderDetailList(orderDetails);
                //设置订单菜品信息
                orderVO.setOrderDishes(orderDetailMapper.selectNameByOrderId(orderId));
                //设置地址信息
                Long addressBookId = orderMapper.selectAddressBookId(orderId);
                orderVO.setAddress(addressBookMapper.selectAddress(addressBookId));

                records.add(orderVO);
            }
        }

        return new PageResult(orders.getTotal(), records);
    }

    /**
     * 添加拒单原因
     * @param id
     * @param rejectionReason
     */
    public void addRejectionReason(Long id, String rejectionReason) {
        orderMapper.addRejectionReason(id, rejectionReason);
    }

    /**
     * 添加取消原因
     * @param id
     * @param cancelReason
     */
    public void addCancelReason(Long id, String cancelReason) {
        orderMapper.addCancelReson(id, cancelReason);
    }

    /**
     * 客户催单
     * @param id
     */
    public void reminder(Long id) {
        Orders orders = orderMapper.selectByOrderId(id);

        Map map = new HashMap();
        map.put("type", 2); //1为订单提醒 2为客户催单
        map.put("orderId", orders.getId());
        map.put("content", "订单编号：" + orders.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }


}
